Skip to content

fix: block critical recursive delete paths#524

Open
Vasyl198 wants to merge 1 commit into
FailproofAI:mainfrom
Vasyl198:fix/block-rm-rf-critical-paths
Open

fix: block critical recursive delete paths#524
Vasyl198 wants to merge 1 commit into
FailproofAI:mainfrom
Vasyl198:fix/block-rm-rf-critical-paths

Conversation

@Vasyl198

@Vasyl198 Vasyl198 commented Jul 16, 2026

Copy link
Copy Markdown

What

Extends block-rm-rf coverage to deny recursive deletion of critical paths:

  • $HOME, ${HOME}, and home-relative paths such as ~/Documents
  • user home directories such as /home/<user> and /Users/<user>
  • critical system directories such as /var/lib, /var/log, /usr/lib, and /usr/local
  • find / -delete and equivalent home-root targets

An explicit allowPaths entry still permits the configured home-relative path.

Why

The policy previously recognized only the root, ~, and single-segment absolute paths. Common destructive forms could bypass it while ordinary project cleanup should remain allowed.

Addresses #520.

Validation

  • npx vitest run __tests__/hooks/builtin-policies.test.ts -t "block-rm-rf" — 37 passed
  • npx eslint src/hooks/builtin-policies.ts __tests__/hooks/builtin-policies.test.ts
  • npx tsc --noEmit

The full policy test file still has an unrelated pre-existing failure in block-read-outside-cwd allow-path handling. Docker smoke testing was unavailable because Docker Desktop's local API did not become ready.

Summary by CodeRabbit

  • Bug Fixes
    • Improved protection against catastrophic recursive deletions involving home directories, system paths, and critical filesystem locations.
    • Added safeguards for destructive find ... -delete commands targeting critical directories.
    • Confirmed configured safe paths, such as ~/scratch, remain permitted.

@coderabbitai

coderabbitai Bot commented Jul 16, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

blockRmRf now centralizes critical-path detection, blocks additional find -delete cases, and adds parameterized tests for denied targets and an allowed home-relative path.

Changes

Recursive-delete policy

Layer / File(s) Summary
Critical path classification
src/hooks/builtin-policies.ts
Adds isCriticalRecursiveDeletePath to normalize and match root, home, and system-directory targets.
Policy enforcement and coverage
src/hooks/builtin-policies.ts, __tests__/hooks/builtin-policies.test.ts
Uses the helper in blockRmRf, blocks selected find -delete commands, and adds deny and allow cases.
Estimated code review effort: 2 (Simple) ~10 minutes

Possibly related issues

  • FailproofAI/failproofai issue 520 — Directly covers the expanded blockRmRf detection, find -delete blocking, and related tests.

Suggested reviewers: niveditjain

Poem

I hopped through paths both near and far,
And stopped the rm commands before they scar.
Home and root now heed the call,
While scratch may still be used by all.
Tests bloom bright in rows of green—
A careful bunny guards the machine.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: blocking critical recursive delete paths.
Description check ✅ Passed The description covers what, why, and validation, though the type-of-change and checklist sections are omitted.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint install timed out. The project may have too many dependencies for the sandbox.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@Vasyl198
Vasyl198 marked this pull request as ready for review July 16, 2026 11:19
@hermes-exosphere

Copy link
Copy Markdown
Contributor

Automated code review started - full review. Results will be posted here.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
__tests__/hooks/builtin-policies.test.ts (1)

621-630: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add test coverage for $HOME/ relative paths and multiple slashes.

To ensure the edge-case bypasses identified in the implementation review are prevented, consider adding these permutations to the parameterized tests.

♻️ Proposed test additions
     it.each([
       "rm -rf $HOME",
       "rm -rf ${HOME}",
+      "rm -rf $HOME/Documents",
       "rm -rf ~/Documents",
+      "rm -rf ~//Documents",
       "rm -rf /home/chetan",
       "rm -rf /var/lib",
+      "rm -rf //var/lib",
     ])("blocks critical recursive-delete target %s", async (command) => {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@__tests__/hooks/builtin-policies.test.ts` around lines 621 - 630, Extend the
parameterized cases in the “blocks critical recursive-delete target” test to
cover recursive-delete commands using the relative `$HOME/` form and paths
containing multiple slashes. Keep the existing context setup and deny assertion
unchanged, ensuring both added permutations are rejected by policy.fn.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/hooks/builtin-policies.ts`:
- Around line 649-653: Replace the raw-command regex in the find deletion check
with parsed-token analysis: identify an actual find executable invocation,
require a -delete argument, and validate its target paths using the same
critical-path logic as rm handling (including paths such as // and /var/lib).
Preserve the existing deny response while avoiding matches inside quoted
arguments or unrelated commands.
- Around line 634-644: Update isCriticalRecursiveDeletePath to collapse
consecutive slashes in the normalized path before applying the protected-path
checks, so inputs such as //usr and /var//lib match the existing rules. Extend
the home-relative checks to recognize paths beginning with $HOME/ and ${HOME}/
in addition to ~/ while preserving the existing exact home-token handling.

---

Nitpick comments:
In `@__tests__/hooks/builtin-policies.test.ts`:
- Around line 621-630: Extend the parameterized cases in the “blocks critical
recursive-delete target” test to cover recursive-delete commands using the
relative `$HOME/` form and paths containing multiple slashes. Keep the existing
context setup and deny assertion unchanged, ensuring both added permutations are
rejected by policy.fn.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c3323c33-ff33-4b23-a793-c18560c08d85

📥 Commits

Reviewing files that changed from the base of the PR and between 446484b and 259b783.

📒 Files selected for processing (2)
  • __tests__/hooks/builtin-policies.test.ts
  • src/hooks/builtin-policies.ts

Comment on lines +634 to +644
function isCriticalRecursiveDeletePath(token: string): boolean {
const normalized = token.replace(/\/\*$/, "").replace(/\/+$/, "") || (token.startsWith("/") ? "/" : "");
return normalized === "/"
|| normalized === "~"
|| normalized === "$HOME"
|| normalized === "${HOME}"
|| normalized.startsWith("~/")
|| /^\/[A-Za-z_][\w.-]*$/.test(normalized)
|| /^\/(?:home|Users)\/[^/]+$/.test(normalized)
|| /^\/(?:var\/(?:lib|log)|usr\/(?:lib|local))$/.test(normalized);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Fix path normalization to prevent bypasses and include $HOME relative paths.

  1. Multiple slashes bypass: Paths like //usr, //var/lib, or /var//lib will bypass the exact regex matches because multiple consecutive slashes are not collapsed (e.g., //usr is perfectly valid in Bash but fails /^\/[A-Za-z_]/).
  2. Missing $HOME/ coverage: The logic correctly covers ~/ with normalized.startsWith("~/"), but misses $HOME/ and ${HOME}/. This leaves rm -rf $HOME/Documents exposed, contradicting the PR objective to protect home-relative paths.

Normalize paths by collapsing consecutive slashes, and add checks for $HOME/ and ${HOME}/.

🛡️ Proposed fix
 function isCriticalRecursiveDeletePath(token: string): boolean {
-  const normalized = token.replace(/\/\*$/, "").replace(/\/+$/, "") || (token.startsWith("/") ? "/" : "");
+  const normalized = token.replace(/\/{2,}/g, "/").replace(/\/\*$/, "").replace(/\/+$/, "") || (token.startsWith("/") ? "/" : "");
   return normalized === "/"
     || normalized === "~"
     || normalized === "$HOME"
     || normalized === "${HOME}"
     || normalized.startsWith("~/")
+    || normalized.startsWith("$HOME/")
+    || normalized.startsWith("${HOME}/")
     || /^\/[A-Za-z_][\w.-]*$/.test(normalized)
     || /^\/(?:home|Users)\/[^/]+$/.test(normalized)
     || /^\/(?:var\/(?:lib|log)|usr\/(?:lib|local))$/.test(normalized);
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
function isCriticalRecursiveDeletePath(token: string): boolean {
const normalized = token.replace(/\/\*$/, "").replace(/\/+$/, "") || (token.startsWith("/") ? "/" : "");
return normalized === "/"
|| normalized === "~"
|| normalized === "$HOME"
|| normalized === "${HOME}"
|| normalized.startsWith("~/")
|| /^\/[A-Za-z_][\w.-]*$/.test(normalized)
|| /^\/(?:home|Users)\/[^/]+$/.test(normalized)
|| /^\/(?:var\/(?:lib|log)|usr\/(?:lib|local))$/.test(normalized);
}
function isCriticalRecursiveDeletePath(token: string): boolean {
const normalized = token.replace(/\/{2,}/g, "/").replace(/\/\*$/, "").replace(/\/+$/, "") || (token.startsWith("/") ? "/" : "");
return normalized === "/"
|| normalized === "~"
|| normalized === "$HOME"
|| normalized === "${HOME}"
|| normalized.startsWith("~/")
|| normalized.startsWith("$HOME/")
|| normalized.startsWith("${HOME}/")
|| /^\/[A-Za-z_][\w.-]*$/.test(normalized)
|| /^\/(?:home|Users)\/[^/]+$/.test(normalized)
|| /^\/(?:var\/(?:lib|log)|usr\/(?:lib|local))$/.test(normalized);
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/hooks/builtin-policies.ts` around lines 634 - 644, Update
isCriticalRecursiveDeletePath to collapse consecutive slashes in the normalized
path before applying the protected-path checks, so inputs such as //usr and
/var//lib match the existing rules. Extend the home-relative checks to recognize
paths beginning with $HOME/ and ${HOME}/ in addition to ~/ while preserving the
existing exact home-token handling.

Comment on lines +649 to +653
const hasDestructivePath = parseArgvTokens(cmd).some(isCriticalRecursiveDeletePath);

if (/\bfind\s+(?:\/|~|\$HOME|\$\{HOME\})(?=\s|$)[\s\S]*?\s-delete\b/.test(cmd)) {
return deny("Catastrophic deletion blocked");
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Refine find -delete detection to avoid false positives and bypasses.

The current regex for find operates on the raw cmd string:

  1. False positives: Commands like echo "find / -delete" or git commit -m "find / -delete" will incorrectly trigger a block because token boundaries and quotes are ignored.
  2. Bypasses: find // -delete bypasses the exact string match.
  3. Inconsistent coverage: Hardcoding (?:\/|~|\$HOME|\$\{HOME\}) misses other critical paths (like /var/lib) that are correctly protected against rm -rf.

You can fix all of these by leveraging the parsed tokens to verify that find and -delete are actual executable tokens, holding find target paths to the exact same standard as rm.

🛡️ Proposed fix
-  const hasDestructivePath = parseArgvTokens(cmd).some(isCriticalRecursiveDeletePath);
-
-  if (/\bfind\s+(?:\/|~|\$HOME|\$\{HOME\})(?=\s|$)[\s\S]*?\s-delete\b/.test(cmd)) {
-    return deny("Catastrophic deletion blocked");
-  }
+  const tokens = parseArgvTokens(cmd);
+  const hasDestructivePath = tokens.some(isCriticalRecursiveDeletePath);
+
+  const findIdx = tokens.indexOf("find");
+  const deleteIdx = tokens.indexOf("-delete");
+  if (findIdx !== -1 && deleteIdx > findIdx) {
+    const findArgs = tokens.slice(findIdx + 1, deleteIdx);
+    if (findArgs.some(isCriticalRecursiveDeletePath)) {
+      return deny("Catastrophic deletion blocked");
+    }
+  }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const hasDestructivePath = parseArgvTokens(cmd).some(isCriticalRecursiveDeletePath);
if (/\bfind\s+(?:\/|~|\$HOME|\$\{HOME\})(?=\s|$)[\s\S]*?\s-delete\b/.test(cmd)) {
return deny("Catastrophic deletion blocked");
}
const tokens = parseArgvTokens(cmd);
const hasDestructivePath = tokens.some(isCriticalRecursiveDeletePath);
const findIdx = tokens.indexOf("find");
const deleteIdx = tokens.indexOf("-delete");
if (findIdx !== -1 && deleteIdx > findIdx) {
const findArgs = tokens.slice(findIdx + 1, deleteIdx);
if (findArgs.some(isCriticalRecursiveDeletePath)) {
return deny("Catastrophic deletion blocked");
}
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/hooks/builtin-policies.ts` around lines 649 - 653, Replace the
raw-command regex in the find deletion check with parsed-token analysis:
identify an actual find executable invocation, require a -delete argument, and
validate its target paths using the same critical-path logic as rm handling
(including paths such as // and /var/lib). Preserve the existing deny response
while avoiding matches inside quoted arguments or unrelated commands.

@hermes-exosphere

Copy link
Copy Markdown
Contributor

Review failed: Could not clone repository.

@hermes-exosphere

Copy link
Copy Markdown
Contributor

Your PR is awaiting review by a moderator. Till then you can join the Discord for conversation: https://discord.gg/qaFM2uYFb

@hermes-exosphere

Copy link
Copy Markdown
Contributor

Your PR is awaiting review by a moderator. Till then you can join the Discord for conversation: https://discord.befailproof.ai

@hermes-exosphere

Copy link
Copy Markdown
Contributor

Your PR is awaiting review by a reviewer. Till then you can join the Discord for conversation: https://discord.befailproof.ai

@hermes-exosphere

Copy link
Copy Markdown
Contributor

Automated code review started - full review. Results will be posted here.

@hermes-exosphere

Copy link
Copy Markdown
Contributor

Phase 2 in progress - deep code analysis. Detected a focused security-focused PR: extends block-rm-rf with critical path protection. Continuing to Phase 3 (build + test) next.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants